#include <Camera.h>
#include <glut.h>

#include <GameGlobals.h>
#include <BaseObject.h>

Camera::Camera()
:width( Global::GameWindow->GetWRef() )
,height( Global::GameWindow->GetHRef() )
{
	scrollSpeed = 10.0f;
	viewCenter_x = 100;//Global::GameWorldSize.x * 0.5f;
	viewCenter_y = 50;//Global::GameWorldSize.y * 0.5f;
	viewZoom = 1.5f;
	target = 0;
	debug_savedTarget = 0;
	debugMode = 0;
}

Camera::~Camera()
{
}

void Camera::SetWindowPos(float x, float y)
{
	viewCenter_x = x;
	viewCenter_y = y;
	ResizeWindow(width,height);
}

void Camera::MoveWindowPos(float dx, float dy)
{
	viewCenter_x += dx;
	viewCenter_y += dy;
	ResizeWindow(width,height);
}

void Camera::ZoomWindow(float delta)
{
	viewZoom+= delta;
	if(viewZoom < Global::TINY)
		viewZoom = Global::TINY;
	ResizeWindow(width,height);
}

void Camera::SetWindowZoom(float zoom)
{
	viewZoom = zoom;
	if(viewZoom < Global::TINY)
		viewZoom = Global::TINY;
	ResizeWindow(width,height);
}

void Camera::ChangeScrollSpeed(float delta)
{
	scrollSpeed += delta;
	scrollSpeed = std::max<float>( scrollSpeed, Global::TINY );
	std::cerr<<"scrollSpeed: "<<scrollSpeed <<"\n";
}

void Camera::SetScrollSpeed(float speed)
{
	scrollSpeed = speed;
	scrollSpeed = std::max<float>( scrollSpeed, Global::TINY );
	std::cerr<<"scrollSpeed: "<<scrollSpeed <<"\n";
}
		
void Camera::Input(const bool* keys, float fps )
{
	if( debugMode )
	{
		float moveSpeed = 5 * fps * scrollSpeed;
		if( keys[ '8' ] )
			MoveWindowPos(0,moveSpeed);
		if( keys[ '2' ] )
			MoveWindowPos(0,-moveSpeed);	
		if( keys[ '4' ] )
			MoveWindowPos(-moveSpeed,0);
		if( keys[ '6' ] )
			MoveWindowPos(moveSpeed,0);

		if( keys[ '7' ] )
			ChangeScrollSpeed( -0.1f );
		if( keys[ '9' ] )
			ChangeScrollSpeed( 0.1f );

		if( keys[ 'z' ] )
			ZoomWindow( fps );
		if( keys[ 'x' ] )
			ZoomWindow( -fps );
	}
}
		
void Camera::ResizeWindow(int w, int h)
{	
	glutReshapeWindow ( w, h );
	glViewport(0,0,w,h);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	float ratio = (float)w / (float)h;

	float extent_x = ratio * 25.0f;
	float extent_y = 25.0f;

	extent_x *= viewZoom;
	extent_y *= viewZoom;

	float lower_x = viewCenter_x - extent_x;
	float lower_y = viewCenter_y - extent_y;
	float upper_x = viewCenter_x + extent_x;
	float upper_y = viewCenter_y + extent_y;

	// L/R/B/T
	gluOrtho2D(lower_x, upper_x, lower_y, upper_y);
}

void Camera::SetTarget( BaseObject* t )
{
	target = t;
}

truth Camera::HasTarget()
{
	if( target )
		return 1;
	return 0;
}

void Camera::ClearTarget()
{
	target = 0;
}

void Camera::SyncWithTarget(float dt)
{
	if(!target)
		return;

	const float MIN_FOLLOW_DISTANCE = 2.0f;//15.0f;
	const float CATCHUP_SPEED		= 0.01f;
	const float MIN_SPEED			= 0.01f;

	float distance_x = target->t.loc.x - viewCenter_x;
	float distance_y = target->t.loc.y - viewCenter_y;

	float xsgn = static_cast<float>(distance_x > 0 ? 1 : -1 );
	float ysgn = static_cast<float>(distance_y > 0 ? 1 : -1 );

	distance_x = fabs(distance_x);
	distance_y = fabs(distance_y);

	if( distance_x > MIN_FOLLOW_DISTANCE )
		distance_x = std::max<float>( distance_x * CATCHUP_SPEED, MIN_SPEED );
	else
		distance_x = 0;
	
	if( distance_y > MIN_FOLLOW_DISTANCE )
		distance_y = std::max<float>( distance_y * CATCHUP_SPEED, MIN_SPEED );
	else
		distance_y = 0;

	viewCenter_x += xsgn * distance_x;// * dt;
	viewCenter_y += ysgn * distance_y;// * dt;
	ResizeWindow(width,height);
}
		
void Camera::SetDebugMode(truth state)
{
	if(!debugMode && target && state)
	{
		debug_savedTarget = target;
		target = 0;
	}
	if(debugMode && debug_savedTarget && !state)
	{
		target = debug_savedTarget;
		debug_savedTarget = 0;
	}

	debugMode = state;
}